/*
 * pkg_parser.cpp
 *
 *  Created on: 2021年1月27日
 *      Author: kimfeng
 */

#include "pkg_parser.h"
#include "buf_stream.hpp"

boost::tribool pkg_parser::consume(sck_pkg_t &pkg, std::vector<uchar> &payload_buffer,
		uchar input)
{
	uint8_t tmp[4], *p;
	switch (m_state)
	{
	case eStart:
		pkg.magic_id = input;
		m_state = eMagic1;
		return boost::indeterminate;
	case eMagic1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.magic_id;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.magic_id);
		m_state = eMagic2;
		return boost::indeterminate;
	case eMagic2:
		pkg.ver = input;
		m_state = eVer1;
		return boost::indeterminate;
	case eVer1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.ver;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.ver);
		m_state = eVer2;
		return boost::indeterminate;
	case eVer2:
		pkg.req_num = input;
		m_state = eReq1;
		return boost::indeterminate;
	case eReq1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.req_num;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.req_num);
		m_state = eReq2;
		return boost::indeterminate;
	case eReq2:
		pkg.seq_num = input;
		m_state = eSeq1;
		return boost::indeterminate;
	case eSeq1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.seq_num;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.seq_num);
		m_state = eSeq2;
		return boost::indeterminate;
	case eSeq2:
		pkg.type = input;
		m_state = eType1;
		return boost::indeterminate;
	case eType1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.type;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.type);
		m_state = eType2;
		return boost::indeterminate;
	case eType2:
		pkg.pending = input;
		m_state = ePend1;
		return boost::indeterminate;
	case ePend1:
		tmp[1] = input;
		tmp[0] = (uchar)pkg.pending;
		p = &tmp[0];
		buf_read<ushort>(&p, &pkg.pending);
		m_state = ePend2;
		return boost::indeterminate;
	case ePend2:
		pkg.len = input;
		m_state = eLen1;
		return boost::indeterminate;
	case eLen1:
		pkg.len |= (input << 0x08);
		m_state = eLen2;
		return boost::indeterminate;
	case eLen2:
		pkg.len |= (input << 0x10);
		m_state = eLen3;
		return boost::indeterminate;
	case eLen3:
		tmp[3] = input;
		tmp[0] = (uint8_t)(pkg.len & 0x000000FF);
		tmp[1] = (uint8_t)((pkg.len & 0x0000FF00) >> 8);
		tmp[2] = (uint8_t)((pkg.len & 0x00FF0000) >> 16);
		m_state = eLen4;
		p = &tmp[0];
		buf_read<uint>(&p, &pkg.len);
		payload_buffer.clear();
		if (pkg.len > PKG_MAX_PAYLOAD_SIZE)
			return false;
		else if (pkg.len > 0)
			return boost::indeterminate;
		else
		{
			m_state = eStart;
			return true;
		}
	case eLen4:
		payload_buffer.push_back(input);
		if (payload_buffer.size() < pkg.len)
		{
			m_state = eReadPayLoad;
			return boost::indeterminate;
		}
		else
		{
			m_state = eStart;
			return true;
		}
	case eReadPayLoad:
		payload_buffer.push_back(input);
		if (payload_buffer.size() < pkg.len)
			return boost::indeterminate;
		else
		{
			m_state = eStart;
			return true;
		}

	default:
		return false;
	}
}
